<?php

namespace app\index\command;

use app\index\helper\CommandHelper;
use app\src\base\helper\ResultHelper;
use app\src\base\helper\ValidateHelper;
use app\src\sunsun\aq806\action\Aq806DeviceEventAction;
use app\src\sunsun\aq806\action\Aq806PhHisAction;
use app\src\sunsun\aq806\action\Aq806TcpLogAction;
use app\src\sunsun\aq806\action\Aq806TempHisAction;
use app\src\sunsun\aq806\logic\Aq806DeviceEventLogic;
use app\src\sunsun\aq806\logic\Aq806DeviceLogic;
use app\src\sunsun\aq806\model\Aq806DeviceEvent;
use app\src\sunsun\common\action\PushLogAction;
use app\src\sunsun\common\logic\UserDeviceLogic;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;

/**
 * Created by PhpStorm.
 * User: 1
 * Date: 2017-07-10
 * Time: 14:42
 */
class Aq806Command extends Command
{
    protected function initialize(Input $input, Output $output)
    {
        CommandHelper::loadLang(['zh-cn', 'en', 'zh-tw']);
    }

    protected function configure()
    {
        $this->setName('device:aq806')
            ->addOption('interval', '', Option::VALUE_OPTIONAL, 'device event process sleep {interval} seconds', 30)
            ->addOption('size', '', Option::VALUE_OPTIONAL, 'device event process sizes per time', 10)
            ->addOption('type', '', Option::VALUE_OPTIONAL, 'command type, support (process_event,offline,clear)', 'clear')
            ->setDescription('aq806 device event process');
    }

    protected function execute(Input $input, Output $output)
    {
        $size = $input->getOption('size');
        $type = $input->getOption('type');
        $interval = $input->getOption('interval');
        $output->info('type= ' . $type . ' size=' . $size);

        switch (strtolower($type)) {
            case 'process_event':
                $this->process_event($output, $size, $interval);
                break;
            case 'offline':
                $this->offline($output, $size);
                break;
            case 'clear':
                $this->clear($output);
                break;
            default:
                $this->clear($output);
                break;
        }
    }

    private function process_event(Output $output, $size = 30, $interval = 30)
    {

        $output->info('process_event start');
        $deviceEventLogic = new Aq806DeviceEventLogic();
        while (true) {
            sleep($interval);
            $now = time();
            $page = ['curpage' => 1, 'size' => $size];
            $map = ['pro_status' => Aq806DeviceEvent::PRO_STATUS_NOT_PROCESS];
            // 1. 对 sunsun_aq806_device_event 进行了分页查询
            $result = $deviceEventLogic->query($map, $page, "id desc");
            $list = $result['info']['list'];
            $allEntity = [];
            $output->info('process count = ' . count($list));
            $phAction = new Aq806PhHisAction();
            $tempAction = (new Aq806TempHisAction());
            foreach ($list as $item) {
                $id = $item['id'];
                $entity = ['id' => $id, 'update_time' => $now, 'pro_status' => Aq806DeviceEvent::PRO_STATUS_PROCESSED];
                $did = $item['did'];
                $eventType = $item['event_type'];
                $content = json_decode($item['event_info'], JSON_OBJECT_AS_ARRAY);

                // 设备推送过来高温、低温报警不处理
                if ($eventType == Aq806DeviceEvent::Event_Type_Alert_Temp_High
                    || $eventType == Aq806DeviceEvent::Event_Type_Alert_Temp_Low) {
                    $entity['pro_status'] = Aq806DeviceEvent::PRO_STATUS_FAILED;
                    array_push($allEntity, $entity);
                    continue;
                }

                // 数据推送 记录
                if ($eventType == Aq806DeviceEvent::Event_Type_Data_PUSH) {

                    // 记录ph值到数据库中
                    $ret = $phAction->add($did, $content, $item);
                    if (!ResultHelper::isSuccess($ret)) {
                        $entity['pro_status'] = Aq806DeviceEvent::PRO_STATUS_FAILED;
                    } else {
                        if (array_key_exists('ph', $content)) {
                            $ph = $content['ph'];
                            $output->info('ph= ' . $ph);
                            // 根据ph进行推送
                            $this->pushPhEventToUser($output, $did, $item, $ph);
                        }
                    }

                    // 记录t值到数据库中
                    $ret = $tempAction->add($did, $content, $item);
                    if (!ResultHelper::isSuccess($ret)) {
                        $entity['pro_status'] = Aq806DeviceEvent::PRO_STATUS_FAILED;
                    } else {
                        if (array_key_exists('t', $content)) {
                            $t = $content['t'];
                            $result = $this->getUsers($did);
                            if (!ValidateHelper::isSuccess($result)) {
                                $entity['pro_status'] = Aq806DeviceEvent::PRO_STATUS_FAILED;
                            } else {
                                $list = $result['info'];
                                // 根据t进行推送
                                $this->pushTempEventToUser($output, $did, $item, $t, $list);
                            }
                        }
                    }
                    array_push($allEntity, $entity);
                    continue;
                }

                $dyn = array_key_exists("dyn", $content) ? $content['dyn'] : -1;
                $this->pushEventToUser($output, $did, $item, $dyn);

                array_push($allEntity, $entity);
            }

            // 统一更新
            if (count($allEntity) > 0) {
                $result = (new Aq806DeviceEventLogic())->saveAll($allEntity);
                if ($result['status']) {
                    $output->info(' save_all = ' . count($result['info']));
                } else {
                    $output->info(' save_all error = ' . $result['info']);
                }
            }
        }
        $output->info('process_event end');
    }

    protected function pushPhEventToUser(Output $output, $did, $item, $ph)
    {

        $deviceType = $this->getDeviceType($did);

        $output->info('push ph event');
        $result = $this->getUsers($did);
        if (!ValidateHelper::isSuccess($result)) {
            return ResultHelper::error('没有绑定用户或报错');
        }

        $list = $result['info'];
        $ctrl_pwd = CommandHelper::getCtrlPwd($did, new Aq806DeviceLogic());
        if (empty($ctrl_pwd)) {
            return ResultHelper::error('控制密码获取无效');
        }
        $time = $item['create_time'];
        $output->info('wait ph pushing count = ' . count($list));
        foreach ($list as $deviceItem) {
            $uid = $deviceItem['uid'];
            $timezone = intval($deviceItem['timezone']);
            $lang = $deviceItem['lang'];
            $extra = json_decode($deviceItem['extra'], JSON_OBJECT_AS_ARRAY);
            if (!is_array($extra) || !array_key_exists("pwd", $extra) || ($extra['pwd'] != 'sunsun123456' && $extra['pwd'] != $ctrl_pwd)) {
                $output->info('did=' . $did . ' password illegal uid=' . $uid);
                // 密码不一致就不需要处理
                continue;
            }

            if (!array_key_exists('ph_on', $extra) || intval($extra['ph_on']) != 1) {
                //ph推送报警开关关闭情况下 不推送，
                continue;
            }
            $ph_l = array_key_exists('ph_l', $extra) ? $extra['ph_l'] : 0;
            $ph_h = array_key_exists('ph_h', $extra) ? $extra['ph_h'] : 0;
            if ($ph_l > 0 && $ph > 0 && $ph < $ph_l) {
                $eventType = 'ph_l';
                // PH过低报警
                $content = lang('equipment_ph_min', ['ph' => $ph / 100.0, 'ph_min' => $ph_l / 100.0], $lang);
            } elseif ($ph_h > 0 && $ph_h > 0 && $ph > $ph_h) {
                $eventType = 'ph_h';
                $output->error('ph value = ' . $ph);
                $output->error('ph high  = ' . $ph_h);
                // PH过高报警
                $content = lang('equipment_ph_max', ['ph' => $ph / 100.0, 'ph_max' => $ph_h / 100.0], $lang);
            } else {
                // 如果没有就无需推送
                continue;
            }
            // 如果10分钟前 已经推送过该信息
            $isPushed = (new PushLogAction())->log($uid, $did, $eventType);
            if ($isPushed) {
                $output->info('did=' . $did . ' last 10 min had pushed uid=' . $uid);
                continue;
            }
            $localTime = gmdate('H:i:s', $timezone * 3600 + $time);
            $nickname = $deviceItem['device_nickname'];
            $data = [
                'to_uid' => $uid,
                'title' => lang('device_notify_title', ['nickname' => $nickname, 'device_type' => lang($deviceType, '', $lang)], $lang),
                'content' => lang('device_notify_content', ['nickname' => $nickname, 'time' => $localTime, 'content' => $content], $lang)
            ];

            if ($time > time() - 1800) {
                // 半个小时以内的消息才推送，过时消息不推送了
                CommandHelper::pushUMeng($data);
            }
        }
        return ResultHelper::success('处理完成');
    }

    /**
     * 获取需要推送的用户id
     * @param $did
     * @return array
     */
    protected function getUsers($did)
    {
        $result = (new UserDeviceLogic())->query(['did' => $did], ['curpage' => 1, 'size' => 50]);

        if (!ValidateHelper::legalArrayResult($result) || empty($result['info']['list'])) {
            return ResultHelper::error('没有绑定用户,无需推送');
        }
        return ResultHelper::success($result['info']['list']);
    }

    /**
     * 获取设备类型
     * @param $did
     * @return string
     */
    private function getDeviceType($did)
    {
        $deviceType = 'aq806';//
        $type = substr($did, 0, 4);
        if ($type == 'S035') {
            $deviceType = 'aq500';
        } elseif ($type == 'S037') {
            $deviceType = 'aq700';
        }

        return $deviceType;
    }

    protected function pushTempEventToUser(Output $output, $did, $item, $t, $list)
    {

        $deviceType = $this->getDeviceType($did);
        $output->info('push t event');
        $ctrl_pwd = CommandHelper::getCtrlPwd($did, new Aq806DeviceLogic());
        if (empty($ctrl_pwd)) {
            return ResultHelper::error('控制密码获取无效');
        }
        $time = $item['create_time'];
        $output->info('wait t pushing count = ' . count($list));
        foreach ($list as $deviceItem) {
            $uid = $deviceItem['uid'];
            $timezone = intval($deviceItem['timezone']);
            $lang = $deviceItem['lang'];
            $extra = json_decode($deviceItem['extra'], JSON_OBJECT_AS_ARRAY);
            if (!is_array($extra) || !array_key_exists("pwd", $extra) || ($extra['pwd'] != 'sunsun123456' && $extra['pwd'] != $ctrl_pwd)) {
                $output->info('did=' . $did . ' password illegal uid=' . $uid);
                // 密码不一致就不需要处理
                continue;
            }

            if (!array_key_exists('temp_on', $extra) || intval($extra['temp_on']) != 1) {
                //温度推送报警开关关闭情况下 不推送，
                continue;
            }

            $temp_l = array_key_exists('temp_l', $extra) ? $extra['temp_l'] : 0;
            $temp_h = array_key_exists('temp_h', $extra) ? $extra['temp_h'] : 10000;
            if ($temp_l > 0 && $t > 0 && $t < $temp_l) {
                $eventType = 't_l';
                // 温度过低报警
                $content = lang($deviceType . '_temp_min', ['temp' => $t / 10, 'temp_min' => $temp_l / 10], $lang);
            } elseif ($temp_h > 0 && $temp_h > 0 && $t > $temp_h) {
                $eventType = 'temp_h';
                $output->error('temp value = ' . $t);
                $output->error('temp high  = ' . $temp_h);
                // 温度过高报警
                $content = lang($deviceType . '_temp_max', ['temp' => $t / 10.0, 'temp_max' => $temp_h / 10.0], $lang);
            } else {
                // 如果没有就无需推送
                continue;
            }
            // 如果10分钟前 已经推送过该信息
            $isPushed = (new PushLogAction())->log($uid, $did, $eventType);
            if ($isPushed) {
                $output->info('did=' . $did . ' last 10 min had pushed uid=' . $uid);
                continue;
            }
            $localTime = gmdate('H:i:s', $timezone * 3600 + $time);
            $nickname = $deviceItem['device_nickname'];
            $data = [
                'to_uid' => $uid,
                'title' => lang('device_notify_title', ['nickname' => $nickname, 'device_type' => lang($deviceType, '', $lang)], $lang),
                'content' => lang('device_notify_content', ['nickname' => $nickname, 'time' => $localTime, 'content' => $content], $lang)
            ];

            if ($time > time() - 1800) {
                // 半个小时以内的消息才推送，过时消息不推送了
                CommandHelper::pushUMeng($data);
            }
        }
        return ResultHelper::success('处理完成');
    }

    protected function pushEventToUser(Output $output, $did, $item, $dyn)
    {

        $result = $this->getUsers($did);
        if (!ValidateHelper::isSuccess($result)) {
            return ResultHelper::error('没有绑定用户或报错');
        }

        $list = $result['info'];
        $ctrl_pwd = CommandHelper::getCtrlPwd($did, new Aq806DeviceLogic());
        if (empty($ctrl_pwd)) {
            return ResultHelper::error('控制密码获取无效');
        }
        $time = $item['create_time'];
        $eventType = $item['event_type'];
        $output->info('wait pushing count = ' . count($list));
        foreach ($list as $deviceItem) {
            $uid = $deviceItem['uid'];
            $timezone = intval($deviceItem['timezone']);
            $lang = $deviceItem['lang'];
            $extra = json_decode($deviceItem['extra'], JSON_OBJECT_AS_ARRAY);
            if (!is_array($extra) || !array_key_exists("pwd", $extra) || ($extra['pwd'] != 'sunsun123456' && $extra['pwd'] != $ctrl_pwd)) {
                $output->info('did=' . $did . ' password illegal uid=' . $uid);
                // 密码不一致就不需要处理
                continue;
            }

            $deviceType = $this->getDeviceType($did);
            $eventTypeDesc = lang($deviceType . '_event_type_' . $eventType, [], $lang);
            $dyn_desc = $this->getDynDesc($dyn, $lang, $deviceType);
            // 拼接上动态提示内容
            $content = '[' . $eventTypeDesc . ']' . $dyn_desc;

            $localTime = gmdate('H:i:s', $timezone * 3600 + $time);
            $nickname = $deviceItem['device_nickname'];

            if ($eventType != Aq806DeviceEvent::Event_Type_Auto_Tip) {
                // 不是动态提示才记录
                // 如果10分钟前 已经推送过该信息
                $isPushed = (new PushLogAction())->log($uid, $did, $eventType);
                if ($isPushed) {
                    $output->info('did=' . $did . ' last 10 min had pushed uid=' . $uid);
                    continue;
                }
            }

            $data = [
                'to_uid' => $uid,
                'title' => lang('device_notify_title', ['nickname' => $nickname, 'device_type' => lang($deviceType, '', $lang)], $lang),
                'content' => lang('device_notify_content', ['nickname' => $nickname, 'time' => $localTime, 'content' => $content], $lang)
            ];

            if ($time > time() - 1800) {
                // 半个小时以内的消息才推送，过时消息不推送了
                CommandHelper::pushUMeng($data);
            }
        }
        return ResultHelper::success('处理完成');
    }

    private function getDynDesc($dyn, $lang, $deviceType)
    {
        $dyn = intval($dyn);
        if (empty($dyn) || $dyn < 0) return "";
        //照明灯动态
        $light_on = 1;
        $light_off = 2;
        //杀菌灯动态
        $Germicidal_on = 4;
        $Germicidal_off = 8;
        //冲浪泵动态
        $Surfing_pump_on = 16;
        $Surfing_pump_off = 32;
        //模式动态
        $Surfing_pump_auto = 64;
        $Surfing_pump_manual = 128;
        $desc = "";

        if (($dyn & $Surfing_pump_auto) == $Surfing_pump_auto) {
            $desc .= lang($deviceType . '_mode_auto_on', [], $lang) . ',';
        }

        if (($dyn & $Surfing_pump_manual) == $Surfing_pump_manual) {
            $desc .= lang($deviceType . '_mode_auto_ff', [], $lang) . ',';
        }

        if (($dyn & $Surfing_pump_on) == $Surfing_pump_on) {
            $desc .= lang($deviceType . '_mode_surfing_pump_on', [], $lang);
        }
        if (($dyn & $Surfing_pump_off) == $Surfing_pump_off) {
            $desc .= lang($deviceType . '_mode_surfing_pump_off', [], $lang);
        }

        if (($dyn & $Germicidal_on) == $Germicidal_on) {
            $desc .= lang($deviceType . '_mode_lamp_on', [], $lang);
        }
        if (($dyn & $Germicidal_off) == $Germicidal_off) {
            $desc .= lang($deviceType . '_mode_lamp_off', [], $lang);
        }
        if (($dyn & $light_on) == $light_on) {
            $desc .= lang($deviceType . '_mode_light_on', [], $lang);
        }
        if (($dyn & $light_off) == $light_off) {
            $desc .= lang($deviceType . '_mode_light_off', [], $lang);
        }

        return $desc;
    }

    private function offline(Output $output, $size = 10)
    {
        $time = microtime(true);
        $output->info('offline start');
        $result = CommandHelper::offline_notify($size, new Aq806DeviceLogic(), 'aq806');
        $cost_time = microtime(true) - $time;
        if ($result['status']) {
            $cnt = count($result['info']);
            $output->info('effect ' . $cnt);
        }
        $output->info('cost ' . $cost_time . ' s');
        $output->info('offline end');
    }

    private function clear(Output $output)
    {
        $output->highlight('aq806 clear start');
        $now = time();
        $dataTimestamp = $now - 3 * 3600;
        (new Aq806TcpLogAction())->clearExpiredData($dataTimestamp);

        $dataTimestamp = $now - 10 * 3600;
        (new Aq806DeviceEventAction())->clearExpiredData($dataTimestamp);

        $output->highlight('aq806 temp his clear');
        $dataTimestamp = $now - 60 * 24 * 3600;
        (new Aq806TempHisAction())->clearExpiredData($dataTimestamp);

        $output->highlight('aq806 ph his clear');
        $dataTimestamp = $now - 60 * 24 * 3600;
        (new Aq806PhHisAction())->clearExpiredData($dataTimestamp);
        $output->highlight('aq806 clear end');
    }
}